package cn.always.xiajia.admin.sys.service.impl;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.google.common.collect.Sets;

import cn.always.xiajia.admin.sys.entity.SysMenu;
import cn.always.xiajia.admin.sys.entity.SysRole;
import cn.always.xiajia.admin.sys.entity.SysRoleMenu;
import cn.always.xiajia.admin.sys.entity.SysUserDept;
import cn.always.xiajia.admin.sys.entity.SysUserPost;
import cn.always.xiajia.admin.sys.entity.SysUserRole;
import cn.always.xiajia.admin.sys.mapper.SysMenuMapper;
import cn.always.xiajia.admin.sys.service.SysMenuService;
import cn.always.xiajia.admin.sys.service.SysRoleMenuService;
import cn.always.xiajia.admin.sys.service.SysRoleService;
import cn.always.xiajia.admin.sys.service.SysUserDeptService;
import cn.always.xiajia.admin.sys.service.SysUserPostService;
import cn.always.xiajia.admin.sys.service.SysUserRoleService;
import cn.always.xiajia.admin.sys.service.SysUserService;
import cn.always.xiajia.framework.common.entity.AjaxResult;
import cn.always.xiajia.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.always.xiajia.framework.common.exception.util.ServiceExceptionUtil;
import cn.always.xiajia.framework.common.util.ExtArrayUtils;
import cn.always.xiajia.framework.common.util.ExtCollUtil;
import cn.always.xiajia.framework.common.util.ExtCollectionUtils;
import cn.always.xiajia.framework.common.util.ExtStringUtil;
import cn.always.xiajia.framework.mybatis.core.service.impl.BaseServiceImplX;
import cn.hutool.core.collection.CollUtil;

/**
 * 
 * @author xgj
 *
 */
@Service("sysMenuService")
public class SysMenuServiceImpl extends BaseServiceImplX<SysMenuMapper, SysMenu> implements SysMenuService {

	@Resource
	protected SysUserRoleService sysUserRoleService;

	@Resource
	protected SysRoleService sysRoleService;

	@Resource
	protected SysRoleMenuService sysRoleMenuService;

	@Resource
	protected SysUserService sysUserService;

	@Resource
	protected SysUserPostService sysUserPostService;

	@Resource
	protected SysUserDeptService sysUserDeptService;

	@Resource
	protected SysMenuMapper sysMenuMapper;

	/**
	 * 获得权限对应的菜单编号数组
	 *
	 * @param perms 权限标识
	 * @return 数组
	 */
	@Override
	public Set<Long> getMenuIdByPerms(String perms) {
		if (ExtStringUtil.isNotEmpty(perms)) {
			return Collections.emptySet();
		}
		Map<String, Object> param = new HashMap<>();
		param.put("EQ_perms", perms);
		return ExtCollectionUtils.convertSet(xjList(param), SysMenu::getMenuId);
	}

	/**
	 * 判断是否有权限，任一一个即可
	 *
	 * @param userId 用户编号
	 * @param permissions 权限
	 * @return 是否
	 */
	@Override
	public boolean hasAnyPermissions(Long userId, String... permissions) {
		// 如果为空，说明已经有权限
		if (ExtArrayUtils.isEmpty(permissions)) {
			return true;
		}

		// 获得当前登录的角色。如果为空，说明没有权限
		List<SysRole> sysRoles = sysRoleService.getSysRoleByUserId(userId);
		if (ExtCollUtil.isEmpty(sysRoles)) {
			return false;
		}

		// 情况一：遍历判断每个权限，如果有一满足，说明有权限
		for (String permission : permissions) {
			if (hasAnyPermission(sysRoles, permission)) {
				return true;
			}
		}

		// 情况二：如果是超管，也说明有权限
		return sysUserService.isSuperAdmin(userId);
	}

	/**
	 * 判断指定角色，是否拥有该 permission 权限
	 *
	 * @param roles 指定角色数组
	 * @param permission 权限标识
	 * @return 是否拥有
	 */
	protected boolean hasAnyPermission(List<SysRole> roles, String permission) {
		Set<Long> menuIds = getMenuIdByPerms(permission);
		// 采用严格模式，如果权限找不到对应的 Menu 的话，也认为没有权限
		if (CollUtil.isEmpty(menuIds)) {
			return false;
		}

		// 判断是否有权限
		Set<Long> roleIds = ExtCollectionUtils.convertSet(roles, SysRole::getRoleId);
		for (Long menuId : menuIds) {
			// 获得拥有该菜单的角色编号集合
			Set<Long> menuRoleIds = sysRoleMenuService.getRoleIdByMenuId(menuId);
			// 如果有交集，说明有权限
			if (ExtCollUtil.containsAny(menuRoleIds, roleIds)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 判断是否有角色，任一一个即可
	 *
	 * @param roles 角色数组
	 * @return 是否
	 */
	@Override
	public boolean hasAnyRoles(Long userId, String... roles) {
		// 如果为空，说明已经有权限
		if (ExtArrayUtils.isEmpty(roles)) {
			return true;
		}

		// 获得当前登录的角色。如果为空，说明没有权限
		List<SysRole> sysRoles = sysRoleService.getSysRoleByUserId(userId);
		if (ExtCollUtil.isEmpty(sysRoles)) {
			return false;
		}

		// 判断是否有角色
		Set<String> userRoles = ExtCollectionUtils.convertSet(sysRoles, SysRole::getRoleCode);
		return ExtCollUtil.containsAny(userRoles, Sets.newHashSet(roles));
	}

	// ========== 角色-菜单的相关方法 ==========
	/**
	 * 设置角色菜单
	 *
	 * @param roleId 角色编号
	 * @param menuIds 菜单编号集合
	 */
	@Override
	public AjaxResult assignRoleMenu(Long roleId, Set<Long> menuIds) {
		if (roleId == null) {
			return ServiceExceptionUtil.exceptionS(GlobalErrorCodeConstants.BAD_REQUEST);
		}
		// 获得角色拥有菜单编号
		Set<Long> dbMenuIds = sysRoleMenuService.getMenuIdByRoleId(roleId);
		// 计算新增和删除的菜单编号
		Set<Long> menuIdList = ExtCollUtil.emptyIfNull(menuIds);
		// 新增的
		Collection<Long> createMenuIds = ExtCollUtil.subtract(menuIdList, dbMenuIds);
		// 删除的
		Collection<Long> deleteMenuIds = ExtCollUtil.subtract(dbMenuIds, menuIdList);
		// 执行新增和删除。对于已经授权的菜单，不用做任何处理
		if (!ExtCollUtil.isEmpty(createMenuIds)) {
			sysRoleMenuService.saveBatch(ExtCollectionUtils.convertList(createMenuIds, menuId -> {
				SysRoleMenu entity = new SysRoleMenu();
				entity.setRoleId(roleId);
				entity.setMenuId(menuId);
				return entity;
			}));
		}
		if (!ExtCollUtil.isEmpty(deleteMenuIds)) {
			Map<String, Object> param = new HashMap<>();
			param.put("EQ_roleId", roleId);
			param.put("IN_menuId", deleteMenuIds);
			sysRoleMenuService.xjRemove(param);
		}
		return AjaxResult.success();
	}

	/**
	 * 处理角色删除时，删除关联授权数据
	 *
	 * @param roleId 角色编号
	 */
	@Override
	public AjaxResult processRoleDeleted(Long roleId) {
		if (roleId == null) {
			return ServiceExceptionUtil.exceptionS(GlobalErrorCodeConstants.BAD_REQUEST);
		}
		Map<String, Object> param = new HashMap<>();
		param.put("EQ_roleId", roleId);
		sysRoleMenuService.xjRemove(param);
		sysUserRoleService.xjRemove(param);
		return AjaxResult.success();
	}

	/**
	 * 处理菜单删除时，删除关联授权数据
	 *
	 * @param menuId 菜单编号
	 */
	@Override
	public AjaxResult processMenuDeleted(Long menuId) {
		if (menuId == null) {
			return ServiceExceptionUtil.exceptionS(GlobalErrorCodeConstants.BAD_REQUEST);
		}
		Map<String, Object> param = new HashMap<>();
		param.put("EQ_menuId", menuId);
		sysRoleMenuService.xjRemove(param);
		return AjaxResult.success();
	}

	// ========== 用户-角色的相关方法 ==========
	/**
	 * 设置用户角色
	 *
	 * @param userId 角色编号
	 * @param roleIds 角色编号集合
	 */
	@Override
	public AjaxResult assignUserRole(Long userId, Set<Long> roleIds) {
		if (userId == null) {
			return ServiceExceptionUtil.exceptionS(GlobalErrorCodeConstants.BAD_REQUEST);
		}
		// 获得用户拥有角色编号
		Set<Long> dbRoleIds = sysUserRoleService.getRoleIdByUserId(userId);
		// 计算新增和删除的角色编号
		Set<Long> roleIdList = CollUtil.emptyIfNull(roleIds);
		Collection<Long> createRoleIds = CollUtil.subtract(roleIdList, dbRoleIds);
		Collection<Long> deleteRoleIds = CollUtil.subtract(dbRoleIds, roleIdList);
		// 执行新增和删除。对于已经授权的角色，不用做任何处理
		if (!ExtCollUtil.isEmpty(createRoleIds)) {
			sysUserRoleService.saveBatch(ExtCollectionUtils.convertList(createRoleIds, roleId -> {
				SysUserRole entity = new SysUserRole();
				entity.setUserId(userId);
				entity.setRoleId(roleId);
				return entity;
			}));
		}
		if (!ExtCollUtil.isEmpty(deleteRoleIds)) {
			Map<String, Object> param = new HashMap<>();
			param.put("EQ_userId", userId);
			param.put("IN_roleId", deleteRoleIds);
			sysUserRoleService.xjRemove(param);
		}
		return AjaxResult.success();
	}

	/**
	 * 处理用户删除时，删除关联授权数据
	 *
	 * @param userId 用户编号
	 */
	@Override
	public AjaxResult processUserDeleted(Long userId) {
		if (userId == null) {
			return ServiceExceptionUtil.exceptionS(GlobalErrorCodeConstants.BAD_REQUEST);
		}
		Map<String, Object> param = new HashMap<>();
		param.put("EQ_userId", userId);
		sysUserRoleService.xjRemove(param);
		sysUserPostService.xjRemove(param);
		sysUserDeptService.xjRemove(param);
		return AjaxResult.success();
	}

	// ========== 用户-岗位的相关方法 ==========

	/**
	 * 设置用户岗位
	 *
	 * @param userId 角色编号
	 * @param postIds 岗位编号集合
	 */
	@Override
	public AjaxResult assignUserPost(Long userId, Set<Long> postIds) {
		if (userId == null) {
			return ServiceExceptionUtil.exceptionS(GlobalErrorCodeConstants.BAD_REQUEST);
		}
		// 获得用户拥有岗位编号
		Set<Long> dbPostIds = sysUserPostService.getPostIdByUserId(userId);
		// 计算新增和删除的岗位编号
		Set<Long> postIdList = CollUtil.emptyIfNull(postIds);
		Collection<Long> createPostIds = CollUtil.subtract(postIdList, dbPostIds);
		Collection<Long> deletePostIds = CollUtil.subtract(dbPostIds, postIdList);
		// 执行新增和删除。对于已经授权的角色，不用做任何处理
		if (!ExtCollUtil.isEmpty(createPostIds)) {
			sysUserPostService.saveBatch(ExtCollectionUtils.convertList(createPostIds, postId -> {
				SysUserPost entity = new SysUserPost();
				entity.setUserId(userId);
				entity.setPostId(postId);
				return entity;
			}));
		}
		if (!ExtCollUtil.isEmpty(deletePostIds)) {
			Map<String, Object> param = new HashMap<>();
			param.put("EQ_userId", userId);
			param.put("IN_postId", deletePostIds);
			sysUserPostService.xjRemove(param);
		}
		return AjaxResult.success();
	}

	/**
	 * 处理岗位删除时，删除关联授权数据
	 *
	 * @param userId 用户编号
	 */
	@Override
	public AjaxResult processPostDeleted(Long userId) {
		if (userId == null) {
			return ServiceExceptionUtil.exceptionS(GlobalErrorCodeConstants.BAD_REQUEST);
		}
		Map<String, Object> param = new HashMap<>();
		param.put("EQ_userId", userId);
		sysUserPostService.xjRemove(param);
		return AjaxResult.success();
	}

	// ========== 用户-部门的相关方法 ==========
	/**
	 * 设置用户部门
	 *
	 * @param userId 角色编号
	 * @param deptIds 部门编号集合
	 */
	@Override
	public AjaxResult assignUserDept(Long userId, Set<Long> deptIds) {
		if (userId == null) {
			return ServiceExceptionUtil.exceptionS(GlobalErrorCodeConstants.BAD_REQUEST);
		}
		// 获得用户拥有岗位编号
		Set<Long> dbDeptIds = sysUserDeptService.getDeptIdByUserId(userId);
		// 计算新增和删除的岗位编号
		Set<Long> deptIdList = CollUtil.emptyIfNull(deptIds);
		Collection<Long> createDeptIds = CollUtil.subtract(deptIdList, dbDeptIds);
		Collection<Long> deleteDeptIds = CollUtil.subtract(dbDeptIds, deptIdList);
		// 执行新增和删除。对于已经授权的角色，不用做任何处理
		if (!ExtCollUtil.isEmpty(createDeptIds)) {
			sysUserDeptService.saveBatch(ExtCollectionUtils.convertList(createDeptIds, deptId -> {
				SysUserDept entity = new SysUserDept();
				entity.setUserId(userId);
				entity.setDeptId(deptId);
				return entity;
			}));
		}
		if (!ExtCollUtil.isEmpty(deleteDeptIds)) {
			Map<String, Object> param = new HashMap<>();
			param.put("EQ_userId", userId);
			param.put("IN_deptId", deleteDeptIds);
			sysUserDeptService.xjRemove(param);
		}
		return AjaxResult.success();
	}

	/**
	 * 处理部门删除时，删除关联授权数据
	 *
	 * @param userId 用户编号
	 */
	@Override
	public AjaxResult processDeptDeleted(Long userId) {
		if (userId == null) {
			return ServiceExceptionUtil.exceptionS(GlobalErrorCodeConstants.BAD_REQUEST);
		}
		Map<String, Object> param = new HashMap<>();
		param.put("EQ_userId", userId);
		sysUserDeptService.xjRemove(param);
		return AjaxResult.success();
	}

	/**
	 * 获取菜单
	 * 
	 * @param menuId
	 * @return
	 */
	@Override
	public SysMenu getMenuListByMenuId(Long menuId) {
		return sysMenuMapper.selectById(menuId);
	}

	/**
	 * 获取菜单s
	 * 
	 * @param menuIds
	 * @return
	 */
	@Override
	public List<SysMenu> getMenuListByMenuIds(Collection<Long> menuIds) {
		if (ExtCollUtil.isEmpty(menuIds)) {
			return Collections.emptyList();
		}
		Map<String, Object> param = new HashMap<>();
		param.put("IN_menuId", menuIds);
		return xjList(param);
	}

}
